
/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Sapimapi is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Sapimapi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Sapimapi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/
#include <StdAfx.h>

#include <otlkcon_obj2xml.h>
#include <otlkcon_print.h>

HRESULT otlkcon_propValue2xml(LPSPropValue pv, int flags, UINT tabLevel,
            LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore,
            LPFREEBUFFER lpFreeBuffer, char **strBuff, size_t strBuffSize)
{
    HRESULT result = S_OK;
    char *valueStr=0;
    wchar_t *valueWStr=0;
    __int64 i, j;

    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) 
                        > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("<propValue>\n")+1) > strBuffSize )
        return E_OUTOFMEMORY;
    strcat(*strBuff, "<propValue>\n");
    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0,tabLevel++;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("<propTag type='uint32h' value='0x%x' />\n",
        pv->ulPropTag)+1) > strBuffSize )
        return E_OUTOFMEMORY;
    sprintf(*strBuff+strlen(*strBuff), 
        "<propTag type='uint32h' value='0x%x' />\n", 
        pv->ulPropTag);
    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");

    switch( PROP_TYPE(pv->ulPropTag) )
    {
        case PT_I2:
            /* short i */
            if( (strlen(*strBuff)
                +_scprintf("<attr name='value' alias='PT_I2' type='int16' value='%d' />\n", pv->Value.i
                )+1) > strBuffSize )
                return E_OUTOFMEMORY;
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_I2' type='int16' value='%d' />\n", pv->Value.i);
            break;

        case PT_LONG:
            /* long l or ul??*/
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_LONG' type='int32' value='%ld' />\n", pv->Value.l);
            break;

        case PT_R4:
            /* float flt */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_R4' type='float' value='%g' />\n", pv->Value.flt);
            break;

        case PT_R8:
            /* double dbl */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_R8' type='double' value='%g' />\n", pv->Value.dbl);
            break;

        case PT_BOOLEAN:
            /* unsigned short int b*/            
            if( pv->Value.b )
                sprintf(*strBuff+strlen(*strBuff), 
                    "<attr name='value' alias='PT_BOOLEAN' type='bool' value='true' />\n");
            else sprintf(*strBuff+strlen(*strBuff), 
                    "<attr name='value' alias='PT_BOOLEAN' type='bool' value='false' />\n");
            break;

        case PT_CURRENCY:
            /* CURRENCY cur */
            /* ??? not sure about this ??? */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_CURRENCY' type='currency' value='%d%u' />\n", 
                pv->Value.cur.Hi, pv->Value.cur.Lo);
            break;

        case PT_APPTIME:
            /* double at */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_APPTIME' type='double' value='%g' />\n", 
                pv->Value.at);
            break;

        case PT_SYSTIME:
            /* FILETIME ft */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_SYSTIME' type='uint64' value='%u%u' />\n",
                pv->Value.ft.dwHighDateTime, pv->Value.ft.dwLowDateTime );
            break;

        case PT_STRING8:
            /* LPSTR lpszA */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_STRING8' type='string' value='%s' />\n",
                pv->Value.lpszA);
            break;

        case PT_BINARY:
            /* SBinary bin */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_BINARY' type='binary' value='");
            if( flags & OTLKCON_OBJ2XML_SHOW_BINARY )
            {
                char *tmpStr = NULL;
                size_t len = otlkcon_base64Encode(pv->Value.bin.lpb, 
                                 pv->Value.bin.cb, &tmpStr);
                strncpy(*strBuff+strlen(*strBuff), tmpStr, len);
                strcat( *strBuff+strlen(*strBuff), "' />\n" );
            }
            else strcat( *strBuff+strlen(*strBuff), "*binary*' />\n" );
            break;

        case PT_UNICODE:
            /* LPWSTR lpszW */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_UNICODE' type='string' value='%s' />\n",
                pv->Value.lpszW);
            break;

        case PT_CLSID:
            /* LPGUID lpguid */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_CLSID' type='guid' value='%x-%x-%x-%x' />\n",
                pv->Value.lpguid->Data1, pv->Value.lpguid->Data2, 
                pv->Value.lpguid->Data3, (unsigned __int64)(pv->Value.lpguid->Data4));
            break;

        case PT_I8:
            /* LARGE_INTEGER li */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_I8' type='int64' value='%u' />\n",
                pv->Value.li.QuadPart);
            break;

        case PT_MV_I2:
            /* SShortArray MVi */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_I2' type='int16' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVi.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%u</value>\n", pv->Value.MVi.lpi[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_LONG:
            /* SLongArray MVl */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_LONG' type='int32' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVl.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%u</value>\n", pv->Value.MVl.lpl[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_R4:
            /* SRealArray MVflt */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_R4' type='float' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVflt.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%g</value>\n", pv->Value.MVflt.lpflt[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_DOUBLE:
            /* SDoubleArray MVdbl */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_DOUBLE' type='double' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVdbl.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%g</value>\n", pv->Value.MVdbl.lpdbl[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_CURRENCY:
            /* SCurrencyArray MVcur */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_CURRENCY' type='currency' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVcur.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%d%u</value>", pv->Value.cur.Hi, pv->Value.cur.Lo);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_APPTIME:
            /* SAppTimeArray MVat */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_APPTIME' type='double' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVat.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%g</value>\n", pv->Value.MVat.lpat[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_SYSTIME:
            /* SDateTimeArray MVft */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_SYSTIME' type='double' count='%d'>\n",
                pv->Value.MVi.cValues);
            tabLevel++;
            for(j=0; j<pv->Value.MVft.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%u%u</value>", pv->Value.MVft.lpft[j].dwHighDateTime, 
                    pv->Value.MVft.lpft[j].dwLowDateTime );
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_BINARY:
            /* SBinaryArray MVbin */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_BINARY' type='binary' count='%d'>\n",
                pv->Value.MVi.cValues);
            for(j=0; j<pv->Value.MVbin.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), "<value>");
                if( flags & OTLKCON_OBJ2XML_SHOW_BINARY )
                {
       //             otlkcon_base64Encode(pv->Value.bin.lpb, 
        //                    pv->Value.MVbin.lpbin[j].cb, *strBuff+strlen(*strBuff));
                    strcat( *strBuff+strlen(*strBuff), "</value>\n" );
                }
                else strcat( *strBuff+strlen(*strBuff), "*binary*</value>\n" );
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_STRING8:
            /* SLPSTRArray MVszA */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_STRING8' type='string' count='%d'>\n",
                pv->Value.MVi.cValues);
            for(j=0; j<pv->Value.MVszA.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");
              
                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%s</value>", pv->Value.MVszA.lppszA[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_UNICODE:
            /* SWStringArray MVszW */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_UNICODE' type='string' count='%d'>\n",
                pv->Value.MVi.cValues);
            for(j=0; j<pv->Value.MVszW.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%s</value>", pv->Value.MVszW.lppszW[j]);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_CLSID:
            /* SGuidArray MVguid */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_CLSID' type='guid' count='%d'>\n",
                pv->Value.MVi.cValues);
            for(j=0; j<pv->Value.MVguid.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%x-%x-%x-%x</value>\n",
                    pv->Value.MVguid.lpguid[j].Data1, pv->Value.MVguid.lpguid[j].Data2, 
                    pv->Value.MVguid.lpguid[j].Data3, (unsigned __int64)(pv->Value.MVguid.lpguid[j].Data4));
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_MV_I8:
            /* SLargeIntegerArray MVli */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_MV_I8' type='int64' count='%d'>\n",
                pv->Value.MVi.cValues);
            for(j=0; j<pv->Value.MVli.cValues; j++)
            {
                for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                    strcat(*strBuff, " ");

                sprintf(*strBuff+strlen(*strBuff), 
                    "<value>%d</value>", pv->Value.MVli.lpli[j].QuadPart);
            }
            for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
                strcat(*strBuff, " ");
            sprintf(*strBuff+strlen(*strBuff), "</attr>\n");
            break;

        case PT_ERROR:
            /* SCODE err */
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_ERROR' type='uint32h' value='0x%x' />\n", pv->Value.err);
            break;

        case PT_NULL:
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_NULL' type='uint32h' value='0x%x' />\n", pv->Value.x);
            break;

        case PT_OBJECT:
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='PT_OBJECT' type='uint32h' value='0x%x' />\n", pv->Value.x);
            break;

        default:
            sprintf(*strBuff+strlen(*strBuff), 
                "<attr name='value' alias='UNKNOWN' type='uint32h' value='*unknown*' />\n");
            break;
    }

    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    strcat(*strBuff, "</propValue>\n");

    return result;
}


HRESULT otlkcon_row2xml(LPSRow row, int flags, UINT tabLevel,
               LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore,
               LPFREEBUFFER lpFreeBuffer, char **strBuff, size_t strBuffSize )
{
    HRESULT result = S_OK;
    ULONG i,j;

    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("<row count='%d'>\n",
        row->cValues)+1) > strBuffSize )
        return E_OUTOFMEMORY;
    sprintf(*strBuff+strlen(*strBuff), "<row count='%d'>\n",
        row->cValues);

    tabLevel++;
    for(j=0; j<row->cValues; j++)
    {
        if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
            return E_OUTOFMEMORY;
        for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
            strcat(*strBuff, " ");
        if( (strlen(*strBuff)+_scprintf("<column>\n"+1)) > strBuffSize )
            return E_OUTOFMEMORY;
        sprintf(*strBuff+strlen(*strBuff), "<column>\n");

        result = otlkcon_propValue2xml(&(row->lpProps[j]), flags, tabLevel+1, lpAllocateBuffer,
                                lpAllocateMore, lpFreeBuffer, strBuff, strBuffSize);
        if( FAILED(result) )
            return result;

        if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
            return E_OUTOFMEMORY;
        for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
            strcat(*strBuff, " ");
        if( (strlen(*strBuff)+_scprintf("</column>\n"+1)) > strBuffSize )
            return E_OUTOFMEMORY;
        sprintf(*strBuff+strlen(*strBuff), "</column>\n");
    }
    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
            return E_OUTOFMEMORY;
    for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("</row>\n"+1)) > strBuffSize )
            return E_OUTOFMEMORY;
    strcat(*strBuff, "</row>\n");

    return result;
}

HRESULT otlkcon_table2xml(LPMAPITABLE lpTable, LPSPropTagArray propTags, char *id, int flags, 
            UINT tabLevel, LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore,
            LPFREEBUFFER lpFreeBuffer, char **strBuff, size_t strBuffSize)
{
    HRESULT result = S_OK;
    LPSPropTagArray props;
    LPSPropTagArray origProps;
    LPMAPITABLE table = (LPMAPITABLE)lpTable;
    LPSRowSet   tableRows;
    ULONG i, j;

    //Walk through properties, convert to string, make grid

    /* We assume the buffer may already contain a string which will not be */
    /* overwritten.  We thus use BufferSize - StringLength to calculate */
    /* available memory, not just BufferSize */
    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("<object>\n")+1) > strBuffSize )
        return E_OUTOFMEMORY;
    sprintf(*strBuff+strlen(*strBuff), "<object>\n");
    tabLevel++;

    int tmpCount = 0;
    if( table )
    {
        result = HrQueryAllRows(table,NULL,NULL,NULL,0,&tableRows);
        tmpCount = tableRows->cRows;
    }
  
    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
        return E_OUTOFMEMORY;
    for(i=0;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("<table id='%s' count='%d'>\n",
        id, tmpCount)+1) > strBuffSize )
        return E_OUTOFMEMORY;
    sprintf(*strBuff+strlen(*strBuff), "<table id='%s' count='%d'>\n",
        id, tmpCount);
    tabLevel++;

    if( table == NULL )
        goto endTag;

    table->QueryColumns(0, &origProps);
    if( propTags == NULL )
        props = origProps;
    else
        table->SetColumns(propTags, 0);

    result = HrQueryAllRows(table,propTags,NULL,NULL,0,&tableRows);

    for(j=0; j<tableRows->cRows; j++)
    {
        result = otlkcon_row2xml( &(tableRows->aRow[j]), flags, tabLevel+1, 
                    lpAllocateBuffer, lpAllocateMore, lpFreeBuffer, strBuff, 
                    strBuffSize);
        if( FAILED(result) )
            return result;
    }    
    
    table->SetColumns(origProps, 0);
    table->SeekRowApprox(0,1);

endTag:
    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
            return E_OUTOFMEMORY;
    for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("</table>\n"+1)) > strBuffSize )
            return E_OUTOFMEMORY;
    strcat(*strBuff, "</table>\n");

    if( (strlen(*strBuff)+tabLevel*OTLKCON_PROP2XML_TABSPACES+1) > strBuffSize )
            return E_OUTOFMEMORY;
    for(i=0,tabLevel--;i<tabLevel*OTLKCON_PROP2XML_TABSPACES;i++)
        strcat(*strBuff, " ");
    if( (strlen(*strBuff)+_scprintf("</object>\n"+1)) > strBuffSize )
            return E_OUTOFMEMORY;
    strcat(*strBuff, "</object>\n");

    return result;
}

HRESULT otlkcon_obj2xml_begin(char **strBuff, size_t strBuffSize)
{
    HRESULT result = S_OK;

    if( (strlen(*strBuff)+_scprintf("<?xml version=\"1.0\"?>\n<objectroot>\n")+1) > strBuffSize )
        return E_OUTOFMEMORY;
    sprintf(*strBuff+strlen(*strBuff), "<?xml version=\"1.0\"?>\n<objectroot>\n");

    return result;
}

HRESULT otlkcon_obj2xml_end(char **strBuff, size_t strBuffSize)
{
    HRESULT result = S_OK;

    if( (strlen(*strBuff)+_scprintf("</objectroot>\n")+1) > strBuffSize )
        return E_OUTOFMEMORY;
    sprintf(*strBuff+strlen(*strBuff), "</objectroot>\n");

    return result;
}